﻿using kinect_draw.Class;
using Microsoft.Kinect;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace kinect_draw
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {

        #region Kinect Property
        Point Captrue_point;
        /// <summary>
        /// Constant for clamping Z values of camera space points from being negative
        /// </summary>
        private const float InferredZPositionClamp = 0.1f;

        /// <summary>
        /// Size of the RGB pixel in the bitmap
        /// </summary>
        private uint bytesPerPixel = 0;

        /// <summary>
        /// Active Kinect sensor
        /// </summary>
        private KinectSensor kinectSensor = null;

        /// <summary>
        /// Reader for color frames
        /// </summary>
        private ColorFrameReader colorFrameReader = null;

        /// <summary>
        /// Bitmap to display
        /// </summary>
        private WriteableBitmap colorBitmap = null;

        /// <summary>
        /// Intermediate storage for receiving frame data from the sensor
        /// </summary>
        private byte[] colorPixels = null;

        /// <summary>
        /// Coordinate mapper to map one type of point to another
        /// </summary>
        private CoordinateMapper coordinateMapper = null;

        /// <summary>
        /// Reader for body frames
        /// </summary>
        private BodyFrameReader bodyFrameReader = null;

        /// <summary>
        /// Array for the bodies
        /// </summary>
        private Body[] bodies = null;

        #endregion
        /// <summary>
        /// Gets the bitmap to display
        /// </summary>
        public ImageSource ImageSource
        {
            get
            {
                return this.colorBitmap;
            }
        }
        int posX = 100, posY = 100;
        public MainWindow()
        {
            this.getKinect();
            this.DataContext = this;
            InitializeComponent();
            this.currentPoint = new Point(-1, -1);

        }

        #region window event
        private void windowKeyUp(object sender, KeyEventArgs e)
        {
            switch (e.Key)
            {
                case Key.P:

                    DrawingAttributes attribs = new DrawingAttributes();
                    attribs.Color = Colors.Orange;
                    attribs.Height = 5.0;
                    attribs.Width = 5.0;
                    attribs.FitToCurve = true;
                    StylusPointCollection strokePoints = new StylusPointCollection();
                    strokePoints.Add(new StylusPoint(posX++, posY));
                    Stroke oS = new Stroke(strokePoints);
                    oS.DrawingAttributes = attribs;
                    this.canvas_draw.Strokes.Add(oS);
                    break;
            }

        }
        private void windowLoaded(object sender, RoutedEventArgs e)
        {
            this.Canvas_root.fixResoulution(new Size(this.ActualWidth, this.ActualHeight), new Size(1600, 900));

            if (this.bodyFrameReader != null)
            {
                
                this.bodyFrameReader.FrameArrived += this.Reader_FrameArrived;
            }
        }
        private void windowClosing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            this.stopKinect();
        }

        #endregion

        #region function kinect
        /// <summary>
        /// Handles the body frame data arriving from the sensor
        /// </summary>
        /// <param name="sender">object sending the event</param>
        /// <param name="e">event arguments</param>
        private void Reader_FrameArrived(object sender, BodyFrameArrivedEventArgs e)
        {
            bool dataReceived = false;

            using (BodyFrame bodyFrame = e.FrameReference.AcquireFrame())
            {
                if (bodyFrame != null)
                {
                    if (this.bodies == null)
                    {
                        this.bodies = new Body[bodyFrame.BodyCount];
                    }

                    bodyFrame.GetAndRefreshBodyData(this.bodies);
                    dataReceived = true;
                }
            }

            if (dataReceived)
            {
                foreach (Body body in this.bodies)
                {
                    if (body.IsTracked)
                    {
                        IReadOnlyDictionary<JointType, Joint> joints = body.Joints;
                        Dictionary<JointType, Point> jointPoints = new Dictionary<JointType, Point>();
                        foreach (JointType jointType in joints.Keys)
                        {
                            CameraSpacePoint position = joints[jointType].Position;
                            jointPoints[jointType] = this.coordinateMapper.MapBodyPointToScreen(this.Width, this.Height, position, this.kinectSensor.DepthFrameSource.FrameDescription); //MapBodyPointToScreen(this.Width,this.Height,position,this.kinectSensor.DepthFrameSource.FrameDescription);
                        }
                        this.DrawHand(body.HandRightState, jointPoints[JointType.HandRight]);
                    }
                }

            }

        }

        private void DrawHand(HandState handState, Point point)
        {
            this.user_1.setPosition(point);
            switch (handState)
            {
                case HandState.Closed:
                    //drawingContext.DrawEllipse(this.handClosedBrush, null, handPosition, HandSize, HandSize);
                    if (this.currentPoint.X == -1 || this.currentPoint.Y == -1)
                    {
                        this.currentPoint = point;
                    }
                    else
                    {
                        this.Paint(this.currentPoint, point);
                    }
                    break;
                case HandState.Open:
                    //drawingContext.DrawEllipse(this.handOpenBrush, null, handPosition, HandSize, HandSize);
                    this.currentPoint = new Point(-1, -1);
                    break;
                case HandState.Lasso:
                   
                    // drawingContext.DrawEllipse(this.handLassoBrush, null, handPosition, HandSize, HandSize);
                    break;
            }
           


        }
        public void Paint(Point startPoint, Point nextPoint)
        {
            Line line = new Line();
            if (currentPoint.X == -1 && currentPoint.Y == -1)
            {
                currentPoint = new Point();
                currentPoint = startPoint;
            }

            line.Stroke = new SolidColorBrush(Colors.Orange);
            line.StrokeDashCap = PenLineCap.Round;
            line.StrokeStartLineCap = PenLineCap.Round;
            line.StrokeEndLineCap = PenLineCap.Round; 
            line.StrokeDashCap = PenLineCap.Round;
            line.StrokeStartLineCap = PenLineCap.Round;
            line.StrokeEndLineCap = PenLineCap.Round;
            line.StrokeThickness = 10;

            line.X1 = currentPoint.X;
            line.Y1 = currentPoint.Y;
            line.X2 = nextPoint.X;
            line.Y2 = nextPoint.Y;
            currentPoint = nextPoint;

            this.canvas_draw.Children.Add(line);
        }
        Point currentPoint;
        /// <summary>
        /// khoi dong kinect lay hinh anh va skeleton
        /// </summary>
        private void getKinect()
        {
            this.kinectSensor = KinectSensor.GetDefault();

            #region get hinh anh kinect
            this.colorFrameReader = this.kinectSensor.ColorFrameSource.OpenReader();
            this.colorFrameReader.FrameArrived += this.Reader_ColorFrameArrived;
            FrameDescription colorFrameDescription = this.kinectSensor.ColorFrameSource.CreateFrameDescription(ColorImageFormat.Bgra);
            this.bytesPerPixel = colorFrameDescription.BytesPerPixel;
            this.colorPixels = new byte[colorFrameDescription.Width * colorFrameDescription.Height * colorFrameDescription.BytesPerPixel];
            this.colorBitmap = new WriteableBitmap(colorFrameDescription.Width, colorFrameDescription.Height, 96.0, 96.0, PixelFormats.Bgr32, null);
            this.kinectSensor.IsAvailableChanged += this.Sensor_IsAvailableChanged;
            #endregion

            #region get body
            // get the coordinate mapper
            this.coordinateMapper = this.kinectSensor.CoordinateMapper;

            // open the reader for the body frames
            this.bodyFrameReader = this.kinectSensor.BodyFrameSource.OpenReader();
            #endregion

           

            this.kinectSensor.Open();
        }
        /// <summary>
        /// tien trinh chay kinect
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Sensor_IsAvailableChanged(object sender, IsAvailableChangedEventArgs e)
        {

        }
        /// <summary>
        /// lay hinh anh tu camera cua kinect
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Reader_ColorFrameArrived(object sender, ColorFrameArrivedEventArgs e)
        {
            bool colorFrameProcessed = false;

            // ColorFrame is IDisposable
            using (ColorFrame colorFrame = e.FrameReference.AcquireFrame())
            {
                if (colorFrame != null)
                {
                    FrameDescription colorFrameDescription = colorFrame.FrameDescription;
                    if ((colorFrameDescription.Width == this.colorBitmap.PixelWidth) && (colorFrameDescription.Height == this.colorBitmap.PixelHeight))
                    {
                        if (colorFrame.RawColorImageFormat == ColorImageFormat.Bgra)
                        {
                            colorFrame.CopyRawFrameDataToArray(this.colorPixels);
                        }
                        else
                        {
                            colorFrame.CopyConvertedFrameDataToArray(this.colorPixels, ColorImageFormat.Bgra);
                        }

                        colorFrameProcessed = true;
                    }
                }
            }

            // we got a frame, render
            if (colorFrameProcessed)
            {
                this.RenderColorPixels();
            }
        }
        /// <summary>
        /// chuyen hinh anh tu dang color pixel
        /// </summary>
        private void RenderColorPixels()
        {
            this.colorBitmap.WritePixels(
                new Int32Rect(0, 0, this.colorBitmap.PixelWidth, this.colorBitmap.PixelHeight),
                this.colorPixels,
                this.colorBitmap.PixelWidth * (int)this.bytesPerPixel,
                0);
        }
        /// <summary>
        /// tat kinect
        /// va tat cac tien trinh dang chay trong kinect
        /// </summary>
        private void stopKinect()
        {
            if (this.bodyFrameReader != null)
            {
                // BodyFrameReader is IDisposable
                this.bodyFrameReader.Dispose();
                this.bodyFrameReader = null;
            }
            if (this.colorFrameReader != null)
            {
                this.colorFrameReader.Dispose();
                this.colorFrameReader = null;
            }

            if (this.kinectSensor != null)
            {
                this.kinectSensor.Close();
                this.kinectSensor = null;
            }
        }

        #endregion
    }
}
